/**
 * 现代化的文件上传器，支持断点续传功能
 */
class ModernUploader {
    constructor(options) {
        this.options = {
            chunkSize: 2 * 1024 * 1024, // 2MB
            threads: 3,
            ...options
        };
        this.file = null;
        this.chunks = [];
        this.uploadedChunks = new Set();
        this.activeUploads = 0;
        this.completed = false;
    }

    /**
     * 选择文件
     * @param {File} file 
     */
    selectFile(file) {
        this.file = file;
        this.chunks = this.splitFileIntoChunks(file);
        this.uploadedChunks.clear();
        this.activeUploads = 0;
        this.completed = false;
        return this.chunks.length;
    }

    /**
     * 将文件分割成块
     * @param {File} file 
     * @returns {Array}
     */
    splitFileIntoChunks(file) {
        const chunks = [];
        const fileSize = file.size;
        const chunkSize = this.options.chunkSize;
        const totalChunks = Math.ceil(fileSize / chunkSize);

        for (let i = 0; i < totalChunks; i++) {
            const start = i * chunkSize;
            const end = Math.min(start + chunkSize, fileSize);
            chunks.push({
                index: i,
                start: start,
                end: end,
                blob: file.slice(start, end),
                size: end - start
            });
        }

        return chunks;
    }

    /**
     * 生成文件唯一标识符
     * @param {File} file 
     * @returns {Promise<string>}
     */
    async generateFileIdentifier(file) {
        // 使用文件名、大小和最后修改时间生成标识符
        const fileData = file.name + file.size + file.lastModified;
        const encoder = new TextEncoder();
        const data = encoder.encode(fileData);
        const hashBuffer = await crypto.subtle.digest('SHA-256', data);
        const hashArray = Array.from(new Uint8Array(hashBuffer));
        return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
    }

    /**
     * 检查分片是否已上传
     * @param {string} identifier 
     * @param {number} chunkIndex 
     * @param {number} totalChunks 
     * @param {number} chunkSize 
     * @param {number} totalSize 
     * @param {string} filename 
     * @returns {Promise<boolean>}
     */
    async checkChunk(identifier, chunkIndex, totalChunks, chunkSize, totalSize, filename) {
        try {
            const response = await fetch(`/chunk/check?identifier=${identifier}&chunkNumber=${chunkIndex + 1}&totalChunks=${totalChunks}&chunkSize=${chunkSize}&totalSize=${totalSize}&filename=${encodeURIComponent(filename)}&relativePath=`);
            const data = await response.json();
            return data.exists || false;
        } catch (error) {
            console.error('检查分片时出错:', error);
            return false;
        }
    }

    /**
     * 上传单个分片
     * @param {string} identifier 
     * @param {Object} chunk 
     * @param {number} totalChunks 
     * @param {number} chunkSize 
     * @param {number} totalSize 
     * @param {string} filename 
     * @returns {Promise<boolean>}
     */
    async uploadChunk(identifier, chunk, totalChunks, chunkSize, totalSize, filename) {
        const formData = new FormData();
        formData.append('file', chunk.blob);
        formData.append('identifier', identifier);
        formData.append('chunkNumber', chunk.index + 1);
        formData.append('totalChunks', totalChunks);
        formData.append('chunkSize', chunkSize);
        formData.append('totalSize', totalSize);
        formData.append('filename', filename);
        formData.append('relativePath', '');

        try {
            const response = await fetch('/chunk/upload', {
                method: 'POST',
                body: formData
            });

            if (response.ok) {
                return true;
            } else {
                console.error('上传分片失败:', await response.text());
                return false;
            }
        } catch (error) {
            console.error('上传分片时出错:', error);
            return false;
        }
    }

    /**
     * 合并分片
     * @param {string} identifier 
     * @param {number} totalChunks 
     * @param {number} chunkSize 
     * @param {number} totalSize 
     * @param {string} filename 
     * @returns {Promise<boolean>}
     */
    async mergeChunks(identifier, totalChunks, chunkSize, totalSize, filename) {
        try {
            const response = await fetch('/chunk/merge', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                body: `identifier=${identifier}&totalChunks=${totalChunks}&chunkSize=${chunkSize}&totalSize=${totalSize}&filename=${encodeURIComponent(filename)}&relativePath=`
            });

            if (response.ok) {
                const data = await response.json();
                return data.message === '合并成功';
            } else {
                console.error('合并分片失败:', await response.text());
                return false;
            }
        } catch (error) {
            console.error('合并分片时出错:', error);
            return false;
        }
    }

    /**
     * 开始上传文件
     * @param {Function} onProgress 进度回调函数
     * @param {Function} onComplete 完成回调函数
     * @param {Function} onError 错误回调函数
     */
    async startUpload(onProgress, onComplete, onError) {
        if (!this.file) {
            onError && onError('未选择文件');
            return;
        }

        try {
            const identifier = await this.generateFileIdentifier(this.file);
            const totalChunks = this.chunks.length;
            const chunkSize = this.options.chunkSize;
            const totalSize = this.file.size;
            const filename = this.file.name;

            // 检查已上传的分片
            for (let i = 0; i < this.chunks.length; i++) {
                if (this.uploadedChunks.has(i)) continue;

                const exists = await this.checkChunk(identifier, i, totalChunks, chunkSize, totalSize, filename);
                if (exists) {
                    this.uploadedChunks.add(i);
                    onProgress && onProgress(this.uploadedChunks.size, totalChunks);
                }
            }

            // 上传未完成的分片
            const uploadPromises = [];
            for (let i = 0; i < this.chunks.length; i++) {
                if (this.uploadedChunks.has(i)) continue;

                // 控制并发数量
                while (this.activeUploads >= this.options.threads) {
                    await new Promise(resolve => setTimeout(resolve, 100));
                }

                this.activeUploads++;
                const chunk = this.chunks[i];
                const uploadPromise = this.uploadChunk(identifier, chunk, totalChunks, chunkSize, totalSize, filename)
                    .then(success => {
                        this.activeUploads--;
                        if (success) {
                            this.uploadedChunks.add(i);
                            onProgress && onProgress(this.uploadedChunks.size, totalChunks);
                        } else {
                            throw new Error(`上传分片 ${i + 1} 失败`);
                        }
                    })
                    .catch(error => {
                        this.activeUploads--;
                        throw error;
                    });

                uploadPromises.push(uploadPromise);
            }

            // 等待所有分片上传完成
            await Promise.all(uploadPromises);

            // 合并分片
            const mergeSuccess = await this.mergeChunks(identifier, totalChunks, chunkSize, totalSize, filename);
            if (mergeSuccess) {
                this.completed = true;
                onComplete && onComplete();
            } else {
                throw new Error('合并分片失败');
            }
        } catch (error) {
            console.error('上传过程中出错:', error);
            onError && onError(error.message);
        }
    }

    /**
     * 暂停上传
     */
    pauseUpload() {
        // 在当前实现中，暂停功能需要更复杂的实现
        // 这里简单地记录状态
        console.log('上传已暂停');
    }

    /**
     * 取消上传
     */
    cancelUpload() {
        this.file = null;
        this.chunks = [];
        this.uploadedChunks.clear();
        this.activeUploads = 0;
        this.completed = false;
        console.log('上传已取消');
    }

    /**
     * 获取上传进度
     * @returns {number} 进度百分比
     */
    getProgress() {
        if (!this.chunks.length) return 0;
        return Math.round((this.uploadedChunks.size / this.chunks.length) * 100);
    }

    /**
     * 是否上传完成
     * @returns {boolean}
     */
    isCompleted() {
        return this.completed;
    }
}

// 导出类
window.ModernUploader = ModernUploader;